package pagesearch

import (
	"fmt"
	"image/color"
	"time"

	"gioui.org/font/gofont"
	"gioui.org/layout"
	"gioui.org/op/clip"
	"gioui.org/op/paint"
	"gioui.org/text"
	"gioui.org/unit"
	"gioui.org/widget"
	"gioui.org/widget/material"
	"gioui.org/x/component"
	"gioui.org/x/richtext"
	"git.sr.ht/~mil/transito/uicomponents/divider"
	"git.sr.ht/~mil/transito/uicomponents/selectlist"
	"git.sr.ht/~mil/transito/uistate"
	"git.sr.ht/~mil/transito/utillinkhandler"
)

type PageSearch struct {
	UIState *uistate.UIState
	list    widget.List

	richtextSelected richtext.InteractiveText

	clickableSearch     widget.Clickable
	clickableSetFrom    widget.Clickable
	clickableSetTo      widget.Clickable
	selectList          selectlist.SelectList
	selectListItems     []string
	TimerStartNominatim *time.Time
	textfieldSearch     component.TextField
}

func Initialize(u *uistate.UIState) PageSearch {
	widget := PageSearch{
		UIState: u,
		list:    widget.List{List: layout.List{Axis: layout.Vertical}},

		selectList: selectlist.SelectList{
			List:       widget.List{List: layout.List{Axis: layout.Vertical}},
			ItemHeight: unit.Dp(24),
			Theme:      u.Theme,
		},
		selectListItems:     []string{},
		TimerStartNominatim: nil,
		textfieldSearch:     component.TextField{},
	}
	widget.UIState.Theme.Shaper = text.NewShaper(text.WithCollection(gofont.Collection()))
	return widget
}

func (widget *PageSearch) Render(gtx layout.Context) layout.Dimensions {
	utillinkhandler.HandleLinkEvents(widget.UIState.Window, &widget.richtextSelected)

	widgetBtnSearch := wgToWidget(widget, wgButtonSearch)

	widgetTextfieldSearch := func(gtx layout.Context) layout.Dimensions {
		gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(15))
		widget.textfieldSearch.SingleLine = true
		return widget.textfieldSearch.Layout(gtx, widget.UIState.Theme, "Nominatim Search")
	}

	widgetSelectList := func(gtx layout.Context) layout.Dimensions {
		gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(20))
		gtx.Constraints.Max.Y = gtx.Dp(unit.Dp(150))

		return widget.selectList.Layout(
			gtx,
			len(widget.selectListItems),
			func(gtx layout.Context, index int) layout.Dimensions {
				defer clip.Rect{Max: gtx.Constraints.Max}.Push(gtx.Ops).Pop()
				switch {
				case widget.selectList.Selected == index:
					paint.Fill(gtx.Ops, color.NRGBA{R: 0xFF, G: 0xF0, B: 0xF0, A: 0xFF})
				case widget.selectList.Hovered == index:
					paint.Fill(gtx.Ops, color.NRGBA{R: 0xF0, G: 0xFF, B: 0xF0, A: 0xFF})
				}
				inset := layout.Inset{Top: 1, Right: 4, Bottom: 1, Left: 4}
				return inset.Layout(gtx, material.Body1(widget.UIState.Theme, widget.selectListItems[index]).Layout)
			},
		)
	}

	// Update select list with nominatim timer value when fetching
	if widget.TimerStartNominatim != nil {
		widget.selectListItems = []string{
			fmt.Sprintf("%.1fs", time.Now().Sub(*widget.TimerStartNominatim).Seconds()),
		}
		widget.UIState.Window.Invalidate()
	}

	widgetSearch := func(gtx layout.Context) layout.Dimensions {
		gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(50))
		gtx.Constraints.Max.Y = gtx.Constraints.Min.Y
		return layout.Flex{}.Layout(gtx, layout.Rigid(dimensionsToWidget(layout.Flex{}.Layout(
			gtx,
			layout.Flexed(0.5, widgetTextfieldSearch),
			layout.Flexed(0.01, layout.Spacer{Width: unit.Dp(2)}.Layout),
			layout.Flexed(0.2, widgetBtnSearch),
		))))
	}

	widgetsScroll := []layout.Widget{
		widgetSearch,
		widgetSelectList,
	}

	if widget.selectList.Selected <= len(widget.selectListItems)-1 {
		if label, coords, err := parseLatLon(widget.selectListItems[widget.selectList.Selected]); err == nil {

			widgetBtnSetFrom := func(gtx layout.Context) layout.Dimensions {
				return material.Button(widget.UIState.Theme, &widget.clickableSetFrom, "Set as From").Layout(gtx)
			}
			widgetBtnSetTo := func(gtx layout.Context) layout.Dimensions {
				return material.Button(widget.UIState.Theme, &widget.clickableSetTo, "Set as To").Layout(gtx)
			}

			if widget.clickableSetFrom.Clicked() {
				widget.UIState.LocationFromCoords = coords
				widget.UIState.LocationFromLabel = label
				widget.UIState.TabSelected = 0
				widget.UIState.Window.Invalidate()
			}

			if widget.clickableSetTo.Clicked() {
				widget.UIState.LocationToCoords = coords
				widget.UIState.LocationToLabel = label
				widget.UIState.TabSelected = 0
				widget.UIState.Window.Invalidate()
			}

			selectedSpans := []richtext.SpanStyle{}
			if s, err := widget.UIState.MarkdownRenderer.Render([]byte(fmt.Sprintf(
				"**Selected:**\n\n%s ([%.5f, %.5f](geo:%.5f,%.5f))",
				label, coords[0], coords[1], coords[0], coords[1],
			))); err == nil {
				selectedSpans = s
			}

			widgetSelected := richtext.Text(&widget.richtextSelected, widget.UIState.Theme.Shaper, selectedSpans...).Layout

			widgetButtonsSplit := func(gtx layout.Context) layout.Dimensions {
				gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(50))
				gtx.Constraints.Max.Y = gtx.Constraints.Min.Y
				return layout.Flex{}.Layout(gtx, layout.Rigid(dimensionsToWidget(layout.Flex{}.Layout(
					gtx,
					layout.Flexed(0.2, widgetBtnSetFrom),
					layout.Flexed(0.01, layout.Spacer{Width: unit.Dp(2)}.Layout),
					layout.Flexed(0.2, widgetBtnSetTo),
				))))
			}

			widgetsScroll = append(widgetsScroll,

				divider.Divider(widget.UIState.Theme).Layout,
				widgetSelected, widgetButtonsSplit)
		}
	}

	return material.List(widget.UIState.Theme, &widget.list).Layout(gtx, len(widgetsScroll), func(gtx layout.Context, i int) layout.Dimensions {
		return layout.UniformInset(unit.Dp(16)).Layout(gtx, widgetsScroll[i])
	})
}
